/*
 * Copyright:  2018 smarabbit studio.
 *
 *  Licensed under the Confluent Community License; you may not use this file
 *  except in compliance with the License.  You may obtain a copy of the License at
 *
 *  http://www.confluent.io/confluent-community-license
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 *  WARRANTIES OF ANY KIND, either express or implied.  See the License for the
 *  specific language governing permissions and limitations under the License.
 *
 *  @作   者： 黄开晖 (117227773@qq.com)
 *  @日   期:  2021年5月29日
 */
package com.massyframework.beanskin.runtime.beancontext;

import java.lang.annotation.Annotation;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

import com.massyframework.beanskin.assembly.beans.BeanContextAdapter;
import com.massyframework.beanskin.assembly.beans.BeanExistsException;
import com.massyframework.beanskin.assembly.beans.BeanNotFoundException;

/**
 * 简单的Bean容器
 * @author huangkh
 *
 */
public final class SimpleBeanContext implements BeanContextAdapter {
	
	private Map<String, Object> beanMap;

	/**
	 * 
	 */
	public SimpleBeanContext() {
		this.beanMap = new ConcurrentHashMap<>();
	}
	
	/**
	 * 添加Bean
	 * @param beanName {@link String},bean名称
	 * @param bean {@link Object}, bean实例
	 * @throws BeanExistsException 重复添加同名bean时抛出的例外
	 */
	public void addBean(String beanName, Object bean) throws BeanExistsException {
		if (this.beanMap.putIfAbsent(beanName, bean) != null) {
			throw new BeanExistsException(beanName);
		}
	}

	/**
	 * 判断是否包含指定名称的bean
	 * @param beanName {@link String},bean名称
	 * @return {@link boolean},返回{@code true}表示包含，否则返回{@code false}
	 */
	public boolean containsBean(String beanName) {
		if (beanName == null) return false;
		return this.beanMap.containsKey(beanName);
	}

	/**
	 * 按{@code beanName}获取Bean实例
	 * @param beanName {@link String},bean名称
	 * @return {@link Object}
	 * @throws BeanNotFoundException bean不存在则抛出例外
	 */
	public Object getBean(String beanName) throws BeanNotFoundException {
		Objects.requireNonNull(beanName, "\"beanName\" cannot be null.");
		Object result = this.beanMap.get(beanName);
		if (result == null) {
			throw new BeanNotFoundException(beanName);
		}
		return result;
	}

	/**
	 * 获取{@code beanName}对应的类型
	 * @param beanName  {@link String},bean名称
	 * @return {@link Class},bean类型
	 * @throws BeanNotFoundException bean不存在则抛出例外
	 */
	public Class<?> getBeanType(String beanName) throws BeanNotFoundException {
		Object bean = this.getBean(beanName);
		return bean.getClass();
	}

	/**
	 * 按{@code beanType} 获取所有实现该类的Bean
	 * @param <B>
	 * @param beanType {@link Class},bean类型
	 * @return {@link Map}
	 */
	public <B> Map<String, B> getBeansOfType(Class<B> beanType) {
		Map<String, B> result = new HashMap<>();
		for (Map.Entry<String, Object> entry: this.beanMap.entrySet()) {
			Object bean = entry.getValue();
			if (beanType.isAssignableFrom(bean.getClass())) {
				result.put(entry.getKey(), beanType.cast(bean));
			}
		}
		return result;
	}

	/**
	 * 所有注解{@code annoType}的Bean
	 * @param annoType {@link class},注解类
	 * @return {@link Map}
	 */
	public Map<String, Object> getBeansWithAnnotation(Class<? extends Annotation> annoType) {
		Map<String, Object> result = new HashMap<>();
		for (Map.Entry<String, Object> entry: this.beanMap.entrySet()) {
			Object bean = entry.getValue();
			if (bean.getClass().isAnnotationPresent(annoType)) {
				result.put(entry.getKey(), bean);
			}
		}
		return result;
	}
	
	

	/**
	 * 所有Bean名称
	 * @return {@link List}
	 */
	public List<String> getBeanNames() {
		return new ArrayList<>(this.beanMap.keySet());
	}

}
